/*!
 * Sound manager - A minimal OpenAL wrapper for Ogre3D.
 */
#ifndef SOUNDMANAGER_H_INCLUDE_GUARD
#define SOUNDMANAGER_H_INCLUDE_GUARD

#include <stdio.h>
#include <string>

// Comment this line if you don't have the EAX 2.0 SDK installed.
//#define USEEAX

#ifdef USEEAX
#include "eax.h"
#endif

// ======================================================================================
// OpenAL includes.
// ======================================================================================
#include <al.h>
#include <alc.h>
#include <AL/alut.h>

// ======================================================================================
// Ogre includes.
// ======================================================================================
#include "OgreVector3.h"
#include "OgreQuaternion.h"

#define MAX_AUDIO_BUFFERS   64
#define MAX_AUDIO_SOURCES   16

#define MAX_FILENAME_LENGTH 40

namespace OgreAL
{
	class SoundManager
	{
	private:

		// EAX related.
		ALboolean		mIsEAXPresent;

#ifdef USEEAX
		// EAX 2.0 GUIDs.
		const GUID DSPROPSETID_EAX20_ListenerProperties
			= { 0x306a6a8, 0xb224, 0x11d2, { 0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22 } };

		const GUID DSPROPSETID_EAX20_BufferProperties
			= { 0x306a6a7, 0xb224, 0x11d2, { 0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22 } };

		EAXSet eaxSet; // EAXSet function, retrieved if EAX Extension is supported.
		EAXGet eaxGet; // EAXGet function, retrieved if EAX Extension is supported.
#endif // USEEAX

		bool			mIsInitialized;
		ALCdevice*		mSoundDevice;
		ALCcontext*		mSoundContext;

		std::string		mAudioPath;

		bool			mIsSoundOn;

		// Listener information.
		ALfloat			mListenerPosition[3];
		ALfloat			mListenerVelocity[3];
		ALfloat			mListenerOrientation[6];

		// Audio sources.
		size_t			mAudioSourcesInUseCount;
		ALuint			mAudioSources[MAX_AUDIO_SOURCES];
		bool			mAudioSourcesInUse[MAX_AUDIO_SOURCES];

		// Audio buffers.
		size_t			mAudioBuffersInUseCount;
		ALuint			mAudioBuffers[MAX_AUDIO_BUFFERS];
		bool			mAudioBuffersInUse[MAX_AUDIO_BUFFERS];
		char			mAudioBuffersFileName[MAX_AUDIO_BUFFERS][MAX_FILENAME_LENGTH];

		// Check if a file is already loaded into a buffer.
		int locateAudioBuffer(const std::string& filename);
		int loadAudioInToSystem(const std::string& filename);
		bool loadWAV(const std::string& filename, ALuint destAudioBuffer);

		// Ogg Vorbis extension.
		//ALboolean		mIsOggVorbisPresent;
		//bool loadOGG(const std::string& filename, ALuint destAudioBuffer);

	public:

		static SoundManager* mSoundManager;

		// Constructor.
		SoundManager(void);
		// Destructor.
		~SoundManager(void);

		static SoundManager* createManager(void);
		static SoundManager* getSingletonPtr(void);

		void SoundManager::selfDestruct(void);

		bool init(void);
		bool isSoundOn(void);
		void setAudioPath(const std::string& audioPath);

		bool checkALError(void);

		std::string listAvailableDevices(void);

		// Acquire an audio source.
		bool loadAudio(const std::string& filename, ALuint* audioID, bool loop);
		bool releaseAudio(ALuint audioID);

		bool playAudio(ALuint audioID, bool forceRestart);
		bool stopAudio(ALuint audioID);
		bool stopAllAudio(void);

		bool pauseAudio(ALuint audioID);
		bool pauseAllAudio(void);
		bool resumeAudio(ALuint audioID);
		bool resumeAllAudio(void);

		bool setSource(ALuint audioID, const Ogre::Vector3& sourcePosition, const Ogre::Vector3& sourceVelocity,
			const float sourceGain = 1.0f, const float sourcePitch = 1.0f);

		bool setSourcePosition(ALuint audioID, const Ogre::Vector3& sourcePosition);
		bool setSourceVelocity(ALuint audioID, const Ogre::Vector3& sourceVelocity);
		bool setSourceGain(ALuint audioID, const float sourceGain);
		bool setSourcePitch(ALuint audioID, const float sourcePitch);

		bool setLoop(ALuint audioID, bool loop);

		bool setListener(const Ogre::Vector3& listererPosition, const Ogre::Vector3& listenerVelocity,
			const Ogre::Vector3& listenerLookAt, const Ogre::Vector3& listenerUp);

		bool setListenerPosition(const Ogre::Vector3& listererPosition);
		bool setListenerVelocity(const Ogre::Vector3& listenerVelocity);
		bool setListenerOrientation(const Ogre::Vector3& listenerLookAt, const Ogre::Vector3& listenerUp);

		//bool isOggExtensionPresent(void);
	};
}

#endif // SOUNDMANAGER_H_INCLUDE_GUARD